import 'dart:math';

import 'package:erp_widget/src/components/picker/base/picker.dart';
import 'package:erp_widget/src/components/picker/base/picker_title.dart';
import 'package:erp_widget/src/components/picker/base/picker_title_config.dart';
import 'package:erp_widget/src/components/picker/date_range/constants.dart';
import 'package:erp_widget/src/components/picker/date_range/time_range_side_widget.dart';
import 'package:erp_widget/src/theme/index.dart';
import 'package:flutter/material.dart';

/// 时间范围选择 TimeRange widget.
// ignore: must_be_immutable
class DxTimeRangeWidget extends StatefulWidget {
  /// 可选最小时间
  final DateTime? minDateTime;

  /// 可选最大时间
  final DateTime? maxDateTime;

  /// 初始开始选中时间
  final DateTime? initialStartDateTime;

  /// 初始结束选中时间
  final DateTime? initialEndDateTime;

  /// 是否限制 Picker 选择的时间范围（开始时间≤结束时间）
  final bool isLimitTimeRange;

  /// 时间格式
  final String? dateFormat;

  /// cancel 回调
  final DateVoidCallback? onCancel;

  /// 选中时间变化时的回调，返回选中的开始、结束时间
  final DateRangeValueCallback? onChange;

  /// 确定回调，返回选中的开始、结束时间
  final DateRangeValueCallback? onConfirm;

  /// Picker title  相关内容配置
  final DxPickerTitleConfig pickerTitleConfig;

  /// 分钟展示的间隔
  final int minuteDivider;

  /// 内部变量，记录左右两侧是否触发了滚动
  bool _isFirstScroll = false, _isSecondScroll = false;

  DxTimeRangeWidget({
    Key? key,
    this.minDateTime,
    this.maxDateTime,
    this.isLimitTimeRange = true,
    this.initialStartDateTime,
    this.initialEndDateTime,
    this.dateFormat = datetimeRangePickerTimeFormat,
    this.pickerTitleConfig = DxPickerTitleConfig.defaultConfig,
    this.minuteDivider = 1,
    this.onCancel,
    this.onChange,
    this.onConfirm,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() => _DxTimePickerWidgetState();
}

class _DxTimePickerWidgetState extends State<DxTimeRangeWidget> {
  late DateTime _minTime, _maxTime;
  late int _currStartHour, _currStartMinute;
  late int _currEndHour, _currEndMinute;
  late List<int> _hourRange, _minuteRange;
  late List<int> _startSelectedIndex;
  late List<int> _endSelectedIndex;
  late DateTime _startSelectedDateTime;
  late DateTime _endSelectedDateTime;
  final DateTime now = DateTime.now();

  void _initData(
    DateTime? minTime,
    DateTime? maxTime,
    DateTime? initStartTime,
    DateTime? initEndTime,
  ) {
    DateTime $minTime = minTime ?? now;
    DateTime $maxTime = maxTime ?? DateTime.parse(datePickerMaxDatetime);
    DateTime $initStartTime = initStartTime ?? now;
    DateTime $initEndTime = initEndTime ?? now;

    _minTime = DateTime(now.year, now.month, now.day, $minTime.hour, $minTime.minute, $minTime.second);
    _maxTime = DateTime(now.year, now.month, now.day, $maxTime.hour, $maxTime.minute, $maxTime.second);

    _currStartHour = $initStartTime.hour;
    _hourRange = _calcHourRange();
    _currStartHour = min(max(_hourRange.first, _currStartHour), _hourRange.last);

    _currStartMinute = $initStartTime.minute;
    _minuteRange = _calcMinuteRange();
    _currStartMinute = min(max(_minuteRange.first, _currStartMinute), _minuteRange.last);
    _currStartMinute -= _currStartMinute % widget.minuteDivider;

    _currEndHour = $initEndTime.hour;
    _currEndHour = min(_currEndHour, _hourRange.last);

    _currEndMinute = $initEndTime.minute;
    _currEndMinute = min(_currEndMinute, _minuteRange.last);
    _currEndMinute -= _currEndMinute % widget.minuteDivider;

    _startSelectedDateTime = DateTime(now.year, now.month, now.day, _currStartHour, _currStartMinute);
    _endSelectedDateTime = DateTime(now.year, now.month, now.day, _currEndHour, _currEndMinute);

    _startSelectedIndex = _calcStartSelectIndexList(widget.minuteDivider);
    _endSelectedIndex = _calcEndSelectIndexList(widget.minuteDivider);
  }

  @override
  void initState() {
    super.initState();
    _initData(widget.minDateTime, widget.maxDateTime, widget.initialStartDateTime, widget.initialEndDateTime);
  }

  @override
  Widget build(BuildContext context) {
    final DxPickerThemeData themeData = DxPickerTheme.of(context);
    _initData(_minTime, _maxTime, _startSelectedDateTime, _endSelectedDateTime);
    return Material(
      color: Colors.transparent,
      child: _renderPickerView(context, themeData),
    );
  }

  /// render simple picker widgets
  Widget _renderPickerView(BuildContext context, DxPickerThemeData themeData) {
    Widget pickerWidget = _renderDatePickerWidget(themeData);

    // display the title widget
    if (widget.pickerTitleConfig.title != null || widget.pickerTitleConfig.showTitle) {
      Widget titleWidget = DxPickerTitle(
        pickerTitleConfig: widget.pickerTitleConfig,
        onCancel: () => _onPressedCancel(),
        onConfirm: () => _onPressedConfirm(),
      );
      return Column(children: <Widget>[titleWidget, pickerWidget]);
    }
    return pickerWidget;
  }

  /// pressed cancel widget
  void _onPressedCancel() {
    if (widget.onCancel != null) {
      widget.onCancel!();
    }
    Navigator.pop(context);
  }

  /// pressed confirm widget
  void _onPressedConfirm() {
    widget.onConfirm?.call(_startSelectedDateTime, _endSelectedDateTime);
    Navigator.pop(context);
  }

  /// render the picker widget of year、month and day
  Widget _renderDatePickerWidget(DxPickerThemeData themeData) {
    /// 用于强制刷新 Widget
    GlobalKey? firstGlobalKey;
    GlobalKey? secondGlobalKey;

    if (widget._isFirstScroll) {
      secondGlobalKey = GlobalKey();
      widget._isFirstScroll = false;
    }
    if (widget._isSecondScroll) {
      firstGlobalKey = GlobalKey();
      widget._isSecondScroll = false;
    }

    List<Widget> pickers = [];
    pickers.add(Expanded(
        flex: 6,
        child: Container(
            height: themeData.pickerHeight,
            color: themeData.backgroundColor,
            child: DxTimeRangeSideWidget(
              key: firstGlobalKey,
              dateFormat: widget.dateFormat,
              minDateTime: _minTime,
              maxDateTime: _maxTime,
              initialStartDateTime: _startSelectedDateTime,
              minuteDivider: widget.minuteDivider,
              onInitSelectChange: (widget.isLimitTimeRange)
                  ? (DateTime selectedDateTime, List<int> selected) {
                      _startSelectedDateTime = selectedDateTime;
                      _startSelectedIndex = selected;
                    }
                  : null,
              onChange: (DateTime selectedDateTime, List<int> selected) {
                setState(() {
                  _startSelectedDateTime = selectedDateTime;
                  _startSelectedIndex = selected;
                  widget._isFirstScroll = true;
                });
              },
            ))));
    pickers.add(_renderDatePickerMiddleColumnComponent(themeData));
    pickers.add(Expanded(
        flex: 6,
        child: Container(
            height: themeData.pickerHeight,
            color: themeData.backgroundColor,
            child: DxTimeRangeSideWidget(
              key: secondGlobalKey,
              dateFormat: widget.dateFormat,
              minDateTime: (widget.isLimitTimeRange) ? _startSelectedDateTime : _minTime,
              maxDateTime: _maxTime,
              initialStartDateTime: (widget.isLimitTimeRange)
                  ? _endSelectedDateTime.compareTo(_startSelectedDateTime) > 0
                      ? _endSelectedDateTime
                      : _startSelectedDateTime
                  : _endSelectedDateTime,
              minuteDivider: widget.minuteDivider,
              onInitSelectChange: (widget.isLimitTimeRange)
                  ? (DateTime selectedDateTime, List<int> selected) {
                      _endSelectedDateTime = selectedDateTime;
                      _endSelectedIndex = selected;
                    }
                  : null,
              onChange: (DateTime selectedDateTime, List<int> selected) {
                setState(() {
                  _endSelectedDateTime = selectedDateTime;
                  _endSelectedIndex = selected;
                  widget._isSecondScroll = true;
                });
              },
            ))));
    return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers);
  }

  /// calculate selected index list
  List<int> _calcStartSelectIndexList(int minuteDivider) {
    int hourIndex = _currStartHour - _hourRange.first;
    int minuteIndex = (_currStartMinute - _minuteRange.first) ~/ minuteDivider;
    return [hourIndex, minuteIndex];
  }

  /// calculate selected index list
  List<int> _calcEndSelectIndexList(int minuteDivider) {
    int hourIndex = _currEndHour - _hourRange.first;
    int minuteIndex = (_currEndMinute - _minuteRange.first) ~/ minuteDivider;
    return [hourIndex, minuteIndex];
  }

  /// calculate the range of hour
  List<int> _calcHourRange() {
    return [_minTime.hour, _maxTime.hour];
  }

  /// calculate the range of minute
  List<int> _calcMinuteRange({currHour}) {
    int minMinute = 0, maxMinute = 59;
    int minHour = _minTime.hour;
    int maxHour = _maxTime.hour;
    currHour ??= _currStartHour;

    if (minHour == currHour) {
      // selected minimum hour, limit minute range
      minMinute = _minTime.minute;
    }
    if (maxHour == currHour) {
      // selected maximum hour, limit minute range
      maxMinute = _maxTime.minute;
    }
    return [minMinute, maxMinute];
  }

  Widget _renderDatePickerMiddleColumnComponent(DxPickerThemeData themeData) {
    return Expanded(
      flex: 1,
      child: Container(
        height: themeData.pickerHeight,
        decoration: BoxDecoration(
            border: const Border(left: BorderSide.none, right: BorderSide.none), color: themeData.backgroundColor),
        child: DxPicker.builder(
          backgroundColor: themeData.backgroundColor,
          lineColor: themeData.dividerColor,
          itemExtent: themeData.itemHeight,
          childCount: 1,
          itemBuilder: (context, index) {
            return Container(
              height: themeData.itemHeight,
              alignment: Alignment.center,
              child: Text('至', style: themeData.itemTextStyle),
            );
          },
          onSelectedItemChanged: (int value) {},
        ),
      ),
    );
  }
}
